package com.conversationboard.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.Date;

import javax.mail.MessagingException;
import javax.naming.NamingException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.conversationboard.cache.BannedUserCache;
import com.conversationboard.captcha.CaptchaService;
import com.conversationboard.config.Configuration;
import com.conversationboard.controller.ipaddress.IPAddress;
import com.conversationboard.email.Mail;
import com.conversationboard.model.PendingRegistration;
import com.conversationboard.model.PendingRegistrations;
import com.conversationboard.model.User;
import com.conversationboard.model.exceptions.UserAlreadyExistsException;
import com.conversationboard.password.PasswordGenerator;
import com.conversationboard.site.Site;
import com.conversationboard.validate.InputChecker;
import com.octo.captcha.service.CaptchaServiceException;
import com.twmacinta.util.MD5;

@WebServlet(name = "RegistrationControllerServlet", urlPatterns = "/RegistrationControllerServlet")
public class RegistrationControllerServlet extends HttpServlet {

	private static final long serialVersionUID = 5141300201080463525L;


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");

		RequestDispatcher failureDispatcher = request.getRequestDispatcher("/Pages/registration-failed.jsp");
		RequestDispatcher successDispatcher = request.getRequestDispatcher("/Pages/registration-successful.jsp");

		/* Security: ensure it was conversation board that submitted this form */

		if (!SecurityChecks.passes(request, this)) {
			/*
			 * Since this is to foil spammers, just forward to the success page
			 * without doing anything.
			 */
			successDispatcher.forward(request, response);
			return;
		}

		String displayName = request.getParameter("name").trim();
		String ipAddress = IPAddress.getIPAddress(request);
		String loginId = request.getParameter("userid").trim();
		String timeZoneString = request.getParameter("timezone");

		if (timeZoneString == null) {
			timeZoneString = "GMT";
		}

		String password = PasswordGenerator.getPassword();

		if (loginId.length() == 0 || displayName.length() == 0 || (!loginId.contains("@"))) {
			request.setAttribute("message",
					"Please set yourself a login ID and a display name. <br /><br /><strong>Your login ID must be a valid email address, since your password will be emailed to this address.</strong>");
			RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/messagepage.jsp");
			dispatcher.forward(request, response);
			return;
		}

		/*
		 * Check for funny formatting. Passwords are OK, they are immediately
		 * MD5d
		 */

		if (InputChecker.containsIllegalCharacter(displayName, ipAddress, loginId) || InputChecker.containsBiDirectionalCodes(loginId, displayName) || loginId.equals("Anonymous")
				|| loginId.contains("%") || displayName.contains("%")) {
			request.setAttribute("message", "Please don't use the following characters in your credentials: <, >, &, %, ', \", `, !, #, {, }, [, ].");
			RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/messagepage.jsp");
			dispatcher.forward(request, response);
			return;
		}

		/*
		 * Don't let a user re-register if their IP address has been banned.
		 * Doesn't really make any difference (they'll be barred by IP number
		 * and not name, except that it should help reduce a pointless buildup
		 * of users.
		 */

		try {

			if (BannedUserCache.isBanned(0, true, loginId, ipAddress)) {
				request.setAttribute("message", "You have been barred from registering.");
				RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/messagepage.jsp");
				dispatcher.forward(request, response);
				return;
			}

			/* Check the CAPTCHA, if it's enabled */

			if (Configuration.getInstance().isCaptchaEnabled()) {

				String captchaId = request.getSession().getId();
				String userTypedIn = request.getParameter("captcha");

				boolean validated = CaptchaService.getInstance().validateResponseForID(captchaId, userTypedIn);

				if (!validated) {
					request.setAttribute("message", "You did not type in the correct letters as shown in the image.");
					failureDispatcher.forward(request, response);
					return;
				}
			}

			/*
			 * Make an MD5 hash of the password, as Tomcat is configured in
			 * $CATALINA_HOME/conf/server.xml in the security realm to have
			 * digest="MD5" in the realm tag, meaning it expects passwords in
			 * the database to be MD5 encoded.
			 */

			MD5 md5 = new MD5();
			md5.Update(password, null);
			String hash = md5.asHex();

			/* Check for legal email address */

			if (!loginId.contains("@")) {
				request.setAttribute("message", "Please enter a valid email address.");
				RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/messagepage.jsp");
				dispatcher.forward(request, response);
				return;
			}

			/* Check to see if user already exists */

			User.checkForExistence(loginId, displayName);

			/*
			 * If the site is set to open, create a user account, and
			 * immediately send an email to the user. If not, store the
			 * registration details temporarily and notify the admins to let
			 * them accept or deny the registration.
			 */

			if (Site.isRegistrationAllowed()) {

				User.add(displayName, loginId, displayName, hash, timeZoneString, ipAddress);

				/*
				 * If we're configured to show the password immediately, forward
				 * it to the page that shows this, otherwise, email it to the
				 * user
				 */

				if (Configuration.getInstance().isShowPasswordImmediately()) {

					request.setAttribute("password", password);

					RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/showpassword.jsp");
					dispatcher.forward(request, response);
					return;

				} else {
					Mail mail = new Mail();
					mail.send("noreply@pleasedonotreplytothisemail.com", loginId, "Successful Registration", "Thankyou for registering. Your password is: " + password);
				}

			} else {
				this.addToPendingRegistrations(displayName, hash, password, loginId, timeZoneString, IPAddress.getIPAddress(request));
			}

			/* Forward to success page */

			successDispatcher.forward(request, response);

		} catch (UserAlreadyExistsException uaee) {

			request.setAttribute("message", uaee.getMessage());
			failureDispatcher.forward(request, response);
			return;

		} catch (SQLException e) {
			throw new ServletException(e);
		} catch (NamingException ne) {
			/* Do Nothing */
		} catch (MessagingException msge) {
			/* Do Nothing */
		} catch (CaptchaServiceException e) {
			/* Do Nothing */
		}
	}


	/**
	 * Get the database's list of pending registrations from the property bag.
	 * 
	 * @param displayName
	 * @param hash
	 * @param loginId
	 * @param timeZone
	 * @throws SQLException
	 */

	private void addToPendingRegistrations(String displayName, String hash, String password, String loginId, String timeZone, String ipAddress) throws SQLException, IOException {

		PendingRegistrations pendingRegistrations = PendingRegistrations.getInstance();

		PendingRegistration pendingRegistration = new PendingRegistration();

		pendingRegistration.setDisplayName(displayName);
		pendingRegistration.setHash(hash);
		pendingRegistration.setPassword(password);
		pendingRegistration.setLoginId(loginId);
		pendingRegistration.setTimeZone(timeZone);
		pendingRegistration.setIpAddress(ipAddress);
		pendingRegistration.setRegistrationTime(new Date());

		pendingRegistrations.add(pendingRegistration);

		pendingRegistrations.store();

	}


	public static void main(String[] args) throws UnsupportedEncodingException {

		MD5 md5 = new MD5();
		md5.Update("hello", null);
		String hash = md5.asHex();

		System.out.println(hash);

	}

}
